package com.fandou.airobot.ui.recording;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.SensorManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.lifecycle.Observer;

import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.SPUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.fandou.airobot.BR;
import com.fandou.airobot.R;
import com.fandou.airobot.database.Record;
import com.fandou.airobot.database.RecordDatabase;
import com.fandou.base.ui.DataBindingConfig;
import com.fandou.base.ui.activity.BaseActivity;
import com.fandou.base.view.CommonShapeButton;
import com.fandou.base.view.NumberStepController;
import com.fandou.videocreator.encoder.AvcEncoder;
import com.jeremyliao.liveeventbus.LiveEventBus;
import com.lxj.xpopup.XPopup;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @author Jm
 * @date 2020/7/9 10:15
 * @description 记录模式拍照activity
 */
public class RecordCameraActivity extends BaseActivity {

    private TextureView mTextureView;
    private CameraManager mCameraManager;
    private CameraDevice mCameraDevice;
    private ImageReader mImageReader;
    private CaptureRequest.Builder mCaptureRequest;
    private CameraDevice.StateCallback mCameraDeviceStateCallback;
    private CameraCaptureSession.StateCallback mCameraCaptureSessionStateCallback;
    private CameraCaptureSession.CaptureCallback mCameraCaptureSessionCaptureCallback;
    private CameraCaptureSession mCameraCaptureSession;
    private String mCurrentCameraId;
    private Size mCurrentSelectSize;
    private Handler mChildHandler;
    private Surface mSurface;


    private LinearLayout llAction;
    private CommonShapeButton csbCancelPreview;
    private ImageView ivConfirm;
    private ImageView ivRepeating;
    private CommonShapeButton csbTakePhoto;
    private CommonShapeButton csbStatus;
    private CommonShapeButton csbExit;
    private CheckBox cbTurn;

    /**
     * 当前的自动拍照间隔
     * default is 0
     */
    private int mInterval = 0;

    @Override
    protected void initViewModel() {
        mViewModel = new CameraViewModel();
    }

    private CameraViewModel mViewModel = null;

    @Override
    protected DataBindingConfig getDataBindingConfig() {
        return new DataBindingConfig(R.layout.ai_robot_recording_camera_activity, mViewModel).addBindingParam(BR.vm, mViewModel);
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.ai_robot_recording_camera_activity);
        mInterval = getIntent().getIntExtra("interval", 0);

        initView();
        observe2SaveRecordingFromVoice();

        initChildThread();
        initCameraManager();
        initSelectCamera();
        initHandlerMatchingSize();
        initTextureViewListener();
        initCameraDeviceStateCallbackListener();
        initCameraCaptureSessionStateCallbackListener();
        initCameraCaptureSessionCaptureCallbackListener();

    }

    @Override
    protected void onResume() {
        super.onResume();
        View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }

    private NumberStepController nscInterval;

    public void initView() {
        llAction = findViewById(R.id.llAction);
        csbCancelPreview = findViewById(R.id.csbCancelPreview);
        ivConfirm = findViewById(R.id.ivConfirm);
        ivRepeating = findViewById(R.id.ivRepeating);
        mTextureView = findViewById(R.id.textureView);

        csbTakePhoto = findViewById(R.id.csbTakePhoto);
        cbTurn = findViewById(R.id.cbTurn);
        cbTurn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mCountDownTimer != null) {
                    mCountDownTimer.cancel();
                }
                reOpenCamera();
            }
        });

        csbTakePhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                takePicture(true);
            }
        });
        initOrientation4Button();

        csbStatus = findViewById(R.id.csbStatus);


        setIntervalInfo(mInterval);

        ConstraintLayout clRecordingSetting = findViewById(R.id.clRecordingSetting);
        csbExit = findViewById(R.id.csbExit);
        csbStatus.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //自动拍照间隔设置
                if (clRecordingSetting.getVisibility() != View.VISIBLE) {
                    clRecordingSetting.setVisibility(View.VISIBLE);
                }
            }
        });


        //关闭记录模式设置
        findViewById(R.id.csbCancel).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clRecordingSetting.setVisibility(View.GONE);
            }
        });

        nscInterval = findViewById(R.id.monitor_setting_period_controller);
        nscInterval.setNumber(mInterval);

        //保存记录间隔设置
        findViewById(R.id.csbSave).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clRecordingSetting.setVisibility(View.GONE);
                mInterval = nscInterval.getNumber();
                SPUtils.getInstance().put(RecordingFragment.SPKEY_RECORDING_INTERVAL, mInterval);
                setIntervalInfo(mInterval);

                //由于重新设置了间隔，so need to 重新开启倒计时
                startCountdown();

            }
        });

        csbExit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showExitTipPop();
            }
        });

        mTextureView.setOnClickListener(mTextureClickListener);
    }

    private View.OnClickListener mTextureClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (csbExit.getVisibility() == View.VISIBLE) {
                csbStatus.setVisibility(View.VISIBLE);
                csbExit.setVisibility(View.GONE);
                csbTakePhoto.setVisibility(View.GONE);
                cbTurn.setVisibility(View.GONE);
            } else {
                csbStatus.setVisibility(View.VISIBLE);
                csbExit.setVisibility(View.VISIBLE);
                csbTakePhoto.setVisibility(View.VISIBLE);
                cbTurn.setVisibility(View.VISIBLE);
            }
        }
    };

    @Override
    public void onBackPressed() {
        showExitTipPop();
    }

    /**
     * 订阅从语音控制里修改间隔， 保存记录
     */
    private void observe2SaveRecordingFromVoice() {
        LiveEventBus.get(AsrExitRecordingEvent.class.getName(), AsrExitRecordingEvent.class).observe(this, new Observer<AsrExitRecordingEvent>() {
            @Override
            public void onChanged(AsrExitRecordingEvent event) {
                switch (event.getAction()) {
                    case AsrExitRecordingEvent.EXIT_AND_SAVE_AUTO:
                        save();
                        break;

                    case AsrExitRecordingEvent.MODIFY_INTERVAL:
                        SPUtils.getInstance().put(RecordingFragment.SPKEY_RECORDING_INTERVAL, event.getInterval());
                        setIntervalInfo(event.getInterval());
                        if (nscInterval != null) {
                            nscInterval.setNumber(event.getInterval());
                        }
                        break;

                    case AsrExitRecordingEvent.TAKE_PHOTO:
                        takePicture(false);
                        break;
                    default:
                        break;
                }

            }
        });
    }

    private RecordingExitTipPop mExitPop;

    /**
     * 点击退出记录模式 或者点击返回键时，显示这个pop
     */
    private void showExitTipPop() {
        // show pop
        mExitPop = (RecordingExitTipPop) new XPopup.Builder(RecordCameraActivity.this)
                .hasShadowBg(false)
                .hasStatusBarShadow(false)
                .dismissOnBackPressed(true)
                .dismissOnTouchOutside(false)
                .asCustom(new RecordingExitTipPop(RecordCameraActivity.this, new RecordingExitTipPop.OnExitListener() {
                    @Override
                    public void onExitRecording(boolean isSave, boolean isSend) {
                        if (isSave) {
                            save();

                        } else {
                            finish();
                        }

                        //isSend do nothing so far
                    }
                }))
                .show();
    }

    private void save() {
        //处理视频
        stopPreview();
        if (mExitPop != null) {
            if (mExitPop.isShow()) {
                mExitPop.dismiss();
            }
            mExitPop = null;
        }
        if (mCountDownTimer != null) {
            mCountDownTimer.cancel();
        }
        loading("正在保存");
        ThreadUtils.executeBySingle(mSavePictureTask);
    }

    /**
     * The task of traverse the picture list and then convert image 2 video in anther task
     */
    private ThreadUtils.Task<List<String>> mSavePictureTask = new ThreadUtils.SimpleTask<List<String>>() {
        @Override
        public List<String> doInBackground() {
            return JpegReaderListener.getFileListByThisTime(RecordCameraActivity.this, mTimestamp);
        }

        @Override
        public void onSuccess(List<String> fileListByThisTime) {
            LogUtils.dTag("CameraActivity", "处理多少张图片：" + fileListByThisTime.size());
            String videoPath = JpegReaderListener.getVideoFileName(RecordCameraActivity.this);
            if (fileListByThisTime.size() > 0) {
                boolean success = imageToVideo(fileListByThisTime
                        , 3  //暂时定为持续3秒
                        , videoPath
                        , new int[]{mCurrentSelectSize.getWidth(), mCurrentSelectSize.getHeight()}
                );

                if (success) {
                    //保存到数据库
                    Record record = new Record(mTimestamp, new File(fileListByThisTime.get(0)).getPath(), videoPath);
                    RecordDatabase.getInstance().recordDao().insertRecord(record);
                    RecordCameraActivity.this.finish();
                } else {
                    showErrorToast("保存失败,请重试");
                }
                endLoading();

            } else {
                finish();
            }
        }
    };

    /**
     * 设置记录模式的信息
     *
     * @param interval minute
     */
    private void setIntervalInfo(int interval) {
        csbStatus.setText(String.format("记录模式(%s分钟/张)", interval));
    }

    /**
     * 倒计时，用于定时拍照
     */
    private CountDownTimer mCountDownTimer;

    private void startCountdown() {
        if (mInterval > 0) {
            //1000 * 60 * 60 * 24 相当于一天时间，一个比较大的值来让倒计时执行。注意，每次都要new
            if (mCountDownTimer != null) {
                mCountDownTimer.cancel();
                mCountDownTimer = null;
            }
            // TODO: 2020/7/9
            mCountDownTimer = new CountDownTimer(1000 * 60 * 60 * 24, mInterval * 1000 * 60) {
                //            mCountDownTimer = new CountDownTimer(1000 * 60 * 60 * 24, 1 * 1000) {
                @Override
                public void onTick(long millisUntilFinished) {
                    LogUtils.dTag("CameraActivity", "millisUntilFinished:" + millisUntilFinished);
                    takePicture(false);
                }

                @Override
                public void onFinish() {
                    LogUtils.dTag("CameraActivity", "onFinish:");
                    //记录模式超过限制，结束，自动保存
                    save();
                }
            };
            mCountDownTimer.start();
        }
    }

    private void initOrientation4Button() {
        OrientationEventListener mOrientationListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {

            @Override
            public void onOrientationChanged(int orientation) {
//                Log.v("CameraActivity", "Orientation changed to " + orientation);
                if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
                    return;  //手机平放时，检测不到有效的角度
                }
//只检测是否有四个角度的改变
                if (orientation > 350 || orientation < 10) { //0度
                    orientation = 0;
                    csbTakePhoto.setRotation(-90);
                    cbTurn.setRotation(-90);
                } else if (orientation > 80 && orientation < 100) { //90度
                    csbTakePhoto.setRotation(180);
                    cbTurn.setRotation(180);
                } else if (orientation > 170 && orientation < 190) { //180度
                    orientation = 180;
                    csbTakePhoto.setRotation(90);
                    cbTurn.setRotation(90);
                } else if (orientation > 260 && orientation < 280) { //270度
                    orientation = 270;
                    csbTakePhoto.setRotation(0);
                    cbTurn.setRotation(0);
                } else {
                    csbTakePhoto.setRotation(0);
                    cbTurn.setRotation(0);
                }
            }
        };

        if (mOrientationListener.canDetectOrientation()) {
            mOrientationListener.enable();
        } else {
            mOrientationListener.disable();
        }
    }


    private void initChildThread() {
        HandlerThread handlerThread = new HandlerThread("faceCamera");
        handlerThread.start();
        mChildHandler = new Handler(handlerThread.getLooper());
    }


    /**
     * 初始化相机管理
     */
    private void initCameraManager() {
        mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    }

    /**
     * 初始化选择摄像头
     */
    private void initSelectCamera() {
        try {
            String[] cameraIdArray = mCameraManager.getCameraIdList();
            for (String itemId : cameraIdArray) {
                CameraCharacteristics itemCharacteristics = mCameraManager.getCameraCharacteristics(itemId);
                Integer facing = itemCharacteristics.get(CameraCharacteristics.LENS_FACING);
                if (facing == CameraCharacteristics.LENS_FACING_BACK) {
                    mCurrentCameraId = itemId;
                    break;
                }

            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        if (mCurrentCameraId == null) {
            finish();
            Toast.makeText(this, "此设备不支持前摄像头", Toast.LENGTH_SHORT).show();
        }

    }

    /**
     * 初始化计算适合当前屏幕分辨率的拍照分辨率
     *
     * @return
     */
    private void initHandlerMatchingSize() {
        try {
            CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCurrentCameraId);
            StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            Size[] sizes = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);
            DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
            int deviceWidth = displayMetrics.widthPixels;
            int deviceHeigh = displayMetrics.heightPixels;
            Log.e("CameraActivity", "当前屏幕密度宽度=" + deviceWidth + "高度=" + deviceHeigh);

            mCurrentSelectSize = new Size(deviceHeigh, deviceWidth);


        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        Log.e("CameraActivity", "当前预览宽度=" + mCurrentSelectSize.getWidth() + "高度=" + mCurrentSelectSize.getHeight());
    }


    private void initTextureViewListener() {
        mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                openCamera(width, height);

            }

            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
                configureTransform(width, height);
            }

            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                return true;
            }

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {

            }
        });
    }

    /**
     * Max preview width that is guaranteed by Camera2 API
     */
    private static final int MAX_PREVIEW_WIDTH = 1920;

    /**
     * Max preview height that is guaranteed by Camera2 API
     */
    private static final int MAX_PREVIEW_HEIGHT = 1080;


    /**
     * Compares two {@code Size}s based on their areas.
     */
    static class CompareSizesByArea implements Comparator<Size> {

        @Override
        public int compare(Size lhs, Size rhs) {
            // We cast here to ensure the multiplications won't overflow
            return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
                    (long) rhs.getWidth() * rhs.getHeight());
        }

    }

    /**
     * Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that
     * is at least as large as the respective texture view size, and that is at most as large as the
     * respective max size, and whose aspect ratio matches with the specified value. If such size
     * doesn't exist, choose the largest one that is at most as large as the respective max size,
     * and whose aspect ratio matches with the specified value.
     *
     * @param choices           The list of sizes that the camera supports for the intended output
     *                          class
     * @param textureViewWidth  The width of the texture view relative to sensor coordinate
     * @param textureViewHeight The height of the texture view relative to sensor coordinate
     * @param maxWidth          The maximum width that can be chosen
     * @param maxHeight         The maximum height that can be chosen
     * @param aspectRatio       The aspect ratio
     * @return The optimal {@code Size}, or an arbitrary one if none were big enough
     */
    private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
                                          int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {

        // Collect the supported resolutions that are at least as big as the preview Surface
        List<Size> bigEnough = new ArrayList<>();
        // Collect the supported resolutions that are smaller than the preview Surface
        List<Size> notBigEnough = new ArrayList<>();
        int w = aspectRatio.getWidth();
        int h = aspectRatio.getHeight();
        for (Size option : choices) {
            if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
                    option.getHeight() == option.getWidth() * h / w) {
                if (option.getWidth() >= textureViewWidth &&
                        option.getHeight() >= textureViewHeight) {
                    bigEnough.add(option);
                } else {
                    notBigEnough.add(option);
                }
            }
        }

        // Pick the smallest of those big enough. If there is no one big enough, pick the
        // largest of those not big enough.
        if (bigEnough.size() > 0) {
            return Collections.min(bigEnough, new CompareSizesByArea());
        } else if (notBigEnough.size() > 0) {
            return Collections.max(notBigEnough, new CompareSizesByArea());
        } else {
            Log.e("CameraActivity", "Couldn't find any suitable preview size");
            return choices[0];
        }
    }


    /**
     * Orientation of the camera sensor
     */
    private int mSensorOrientation;

    /**
     * 标识开始记录的时间
     */
    private long mTimestamp = System.currentTimeMillis();

    /**
     * Sets up member variables related to camera.
     *
     * @param width  The width of available size for camera preview
     * @param height The height of available size for camera preview
     */
    @SuppressWarnings("SuspiciousNameCombination")
    private void setUpCameraOutputs(int width, int height) {
        Activity activity = this;
        CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
        try {
            for (String cameraId : manager.getCameraIdList()) {
                CameraCharacteristics characteristics
                        = manager.getCameraCharacteristics(cameraId);

                // We don't use a front facing camera in this sample.
                Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
                if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                    continue;
                }

                StreamConfigurationMap map = characteristics.get(
                        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                if (map == null) {
                    continue;
                }

                // For still image captures, we use the largest available size.
                Size largest = Collections.max(
                        Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
                        new CompareSizesByArea());
                mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
                        ImageFormat.JPEG, /*maxImages*/2);
                mImageReader.setOnImageAvailableListener(new JpegReaderListener(this, mTimestamp), mChildHandler);

                // Find out if we need to swap dimension to get the preview size relative to sensor
                // coordinate.
                int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
                //noinspection ConstantConditions
                mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
                boolean swappedDimensions = false;
                switch (displayRotation) {
                    case Surface.ROTATION_0:
                    case Surface.ROTATION_180:
                        if (mSensorOrientation == 90 || mSensorOrientation == 270) {
                            swappedDimensions = true;
                        }
                        break;
                    case Surface.ROTATION_90:
                    case Surface.ROTATION_270:
                        if (mSensorOrientation == 0 || mSensorOrientation == 180) {
                            swappedDimensions = true;
                        }
                        break;
                    default:
                        Log.e("CameraActivity", "Display rotation is invalid: " + displayRotation);
                }

                Point displaySize = new Point();
                activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
                int rotatedPreviewWidth = width;
                int rotatedPreviewHeight = height;
                int maxPreviewWidth = displaySize.x;
                int maxPreviewHeight = displaySize.y;

                if (swappedDimensions) {
                    rotatedPreviewWidth = height;
                    rotatedPreviewHeight = width;
                    maxPreviewWidth = displaySize.y;
                    maxPreviewHeight = displaySize.x;
                }

                if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
                    maxPreviewWidth = MAX_PREVIEW_WIDTH;
                }

                if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
                    maxPreviewHeight = MAX_PREVIEW_HEIGHT;
                }

                // Danger, W.R.! Attempting to use too large a preview size could  exceed the camera
                // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
                // garbage capture data.
                mCurrentSelectSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
                        rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
                        maxPreviewHeight, largest);

                // We fit the aspect ratio of TextureView to the size of preview we picked.
                int orientation = getResources().getConfiguration().orientation;
                if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
//                    mTextureView.setAspectRatio(
//                            mPreviewSize.getWidth(), mPreviewSize.getHeight());
                } else {
//                    mTextureView.setAspectRatio(
//                            mPreviewSize.getHeight(), mPreviewSize.getWidth());
                }

                // Check if the flash is supported.
                Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
//                mFlashSupported = available == null ? false : available;

                mCurrentCameraId = cameraId;
                return;
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
        }
    }

    private void initCameraDeviceStateCallbackListener() {
        mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
            @Override
            public void onOpened(@NonNull CameraDevice camera) {
                //相机开启
                mCameraDevice = camera;
                try {
                    SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
                    surfaceTexture.setDefaultBufferSize(mCurrentSelectSize.getWidth(), mCurrentSelectSize.getHeight());
                    mSurface = new Surface(surfaceTexture);
                    mCaptureRequest = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                    mCaptureRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                    mCaptureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);//自动爆光
                    mCaptureRequest.addTarget(mSurface);
                    mCameraDevice.createCaptureSession(Arrays.asList(mSurface, mImageReader.getSurface())
                            , mCameraCaptureSessionStateCallback
                            , mChildHandler);

                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }


            }

            @Override
            public void onDisconnected(@NonNull CameraDevice camera) {

            }

            @Override
            public void onError(@NonNull CameraDevice camera, int error) {
                finish();
                Toast.makeText(RecordCameraActivity.this, "相机打开失败", Toast.LENGTH_SHORT).show();
                Log.e("CameraActivity", "CameraDevice.StateCallback onError : 相机异常 error code=" + error);

            }
        };
    }

    private void initCameraCaptureSessionStateCallbackListener() {
        mCameraCaptureSessionStateCallback = new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(@NonNull CameraCaptureSession session) {
                mCameraCaptureSession = session;
                startPreview();
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        startCountdown();
                    }
                },500);

            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                finish();
                Toast.makeText(RecordCameraActivity.this, "相机打开失败", Toast.LENGTH_SHORT).show();
                Log.e("CameraActivity", "CameraCaptureSession.StateCallback onConfigureFailed : CameraCaptureSession会话通道创建失败");

            }
        };
    }

    private void initCameraCaptureSessionCaptureCallbackListener() {
        mCameraCaptureSessionCaptureCallback = new CameraCaptureSession.CaptureCallback() {
            @Override
            public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) {
                super.onCaptureStarted(session, request, timestamp, frameNumber);
                //获取开始
//                startPreview();
//                Log.e("CameraActivity", "onCaptureStarted");

            }

            @Override
            public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
                super.onCaptureProgressed(session, request, partialResult);
                //获取中
//                Log.e("CameraActivity", "onCaptureProgressed");
            }

            @Override
            public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);
                //获取结束
//                Log.e("CameraActivity", "onCaptureCompleted");
            }

            @Override
            public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
                super.onCaptureFailed(session, request, failure);
                //获取失败

                Toast.makeText(RecordCameraActivity.this, "拍照失败", Toast.LENGTH_SHORT).show();
                Log.e("CameraActivity", "失败报告Reason=" + failure.getReason());

            }
        };
    }

    private static final String TAG_PREVIEW = "预览";

    private void repeatPreview() {
        //设置反复捕获数据的请求，这样预览界面就会一直有数据显示
        try {
            mCameraCaptureSession.setRepeatingRequest(mCaptureRequest.build(), mCameraCaptureSessionCaptureCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }

    @SuppressLint("MissingPermission")
    private void openCamera(int width, int height) {
        setUpCameraOutputs(width, height);
        configureTransform(width, height);
        try {
            mCameraManager.openCamera(mCurrentCameraId, mCameraDeviceStateCallback, mChildHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }


    /**
     * 开始预览
     */
    private void startPreview() {
        try {
            mCameraCaptureSession.setRepeatingRequest(mCaptureRequest.build(), mCameraCaptureSessionCaptureCallback, mChildHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 停止预览
     */
    private void stopPreview() {
        try {
            mCameraCaptureSession.stopRepeating();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }

    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();


    static {// /为了使照片竖直显示
        ORIENTATIONS.append(Surface.ROTATION_0, 90);
        ORIENTATIONS.append(Surface.ROTATION_90, 0);
        ORIENTATIONS.append(Surface.ROTATION_180, 270);
        ORIENTATIONS.append(Surface.ROTATION_270, 180);
    }


    /**
     * 拍照
     *
     * @param needShowPreview 是否需要显示预览图。自动拍照或者手动拍照时，是否需要预览图片
     */
    private void takePicture(boolean needShowPreview) {
        try {
            final CaptureRequest.Builder mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);//自动对焦
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);//自动爆光
            int rotation = getWindowManager().getDefaultDisplay().getRotation();
            Log.i("CameraActivity", "getRotations手机方向:" + rotation);
            int angle = getJpegOrientation(mCameraManager.getCameraCharacteristics(mCurrentCameraId), rotation);
//            Log.i("CameraActivity", "照片方向:" + ORIENTATIONS.get(rotation));
//            Log.i("CameraActivity", "照片角度=" + angle);
            mPreviewRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, 0);  //直接写成0 横屏状态的
            Surface surface = mImageReader.getSurface();
            mPreviewRequestBuilder.addTarget(surface);

            if (needShowPreview) {
                mTextureView.setOnClickListener(null);
                mCameraCaptureSession.stopRepeating();
                llAction.setVisibility(View.VISIBLE);
                csbCancelPreview.setVisibility(View.VISIBLE);
                csbCancelPreview.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        toggleAction(true);
                    }
                });
                csbTakePhoto.setVisibility(View.GONE);
                cbTurn.setVisibility(View.GONE);
                csbStatus.setVisibility(View.GONE);
                csbExit.setVisibility(View.GONE);

                //继续拍照
                ivRepeating.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        toggleAction(true);
                    }
                });

                ivConfirm.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        toggleAction(true);
                        try {
                            mCameraCaptureSession.capture(mPreviewRequestBuilder.build(), null, mChildHandler);
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }
                });
            } else {
                mCameraCaptureSession.capture(mPreviewRequestBuilder.build(), null, mChildHandler);
            }

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }

    /**
     * @param keepPreview 继续预览图像。此情况下，隐藏所有操作按钮
     */
    private void toggleAction(boolean keepPreview) {
        if (keepPreview) {
            startPreview();
            mTextureView.setOnClickListener(mTextureClickListener);
            llAction.setVisibility(View.GONE);
            csbCancelPreview.setVisibility(View.GONE);
            csbTakePhoto.setVisibility(View.GONE);
            cbTurn.setVisibility(View.GONE);
            csbStatus.setVisibility(View.VISIBLE);
            csbExit.setVisibility(View.GONE);
        } else {

        }
    }


    /**
     * 官方sample中的
     *
     * @param viewWidth
     * @param viewHeight
     */
    private void configureTransform(int viewWidth, int viewHeight) {
        Activity activity = this;
        if (null == mTextureView || null == mCurrentSelectSize) {
            return;
        }
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        Matrix matrix = new Matrix();
        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        RectF bufferRect = new RectF(0, 0, mCurrentSelectSize.getHeight(), mCurrentSelectSize.getWidth());
        float centerX = viewRect.centerX();
        float centerY = viewRect.centerY();
        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / mCurrentSelectSize.getHeight(),
                    (float) viewWidth / mCurrentSelectSize.getWidth());
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(90 * (rotation - 2), centerX, centerY);
        }
        mTextureView.setTransform(matrix);
    }

    /**
     * 官方提供的JPEG图片方向算法
     *
     * @param c
     * @param deviceOrientation
     * @return
     */
    private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) {
        if (deviceOrientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
            return 0;
        }
        int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);//获取传感器方向

        // Round device orientation to a multiple of 90
        deviceOrientation = (deviceOrientation + 45) / 90 * 90;

        // Reverse device orientation for front-facing cameras
        boolean facingFront = c.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT;//判断摄像头面向
        if (facingFront) {
            deviceOrientation = -deviceOrientation;
        }

        // Calculate desired JPEG orientation relative to camera orientation to make
        // the image upright relative to the device orientation
        int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360;

        return jpegOrientation;
    }


    /**
     * 换cameraID
     */
    @SuppressLint("MissingPermission")
    private void reOpenCamera() {
//        mFocusImage.stopFocus();
        if (mCurrentCameraId.equals("1")) {
            mCurrentCameraId = "0";
        } else if (mCurrentCameraId.equals("0")) {
            mCurrentCameraId = "1";
//            mPreviewSize = new Size(1280, 720);
        } else {
            mCurrentCameraId = "0";
        }
        //关闭相机再开启另外个摄像头
        if (mCameraCaptureSession != null) {
            mCameraCaptureSession.close();
            mCameraCaptureSession = null;
        }
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }

        try {
//            setUpCameraOutputs(viewWidth, viewHeight);
//            configureTransform(viewWidth, viewHeight);
            mCameraManager.openCamera(mCurrentCameraId, mCameraDeviceStateCallback, mChildHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mSavePictureTask != null) {
            ThreadUtils.executeBySingle(mSavePictureTask);
        }
        if (mCountDownTimer != null) {
            mCountDownTimer.cancel();
            mCountDownTimer = null;
        }
        if (mImageReader != null) {
            mImageReader.close();
            mImageReader = null;
        }
        if (mCameraCaptureSession != null) {
            stopPreview();
            try {
                mCameraCaptureSession.abortCaptures();
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
            mCameraCaptureSession.close();
            mCameraCaptureSession = null;
        }
        if (mCaptureRequest != null) {
            mCaptureRequest.removeTarget(mSurface);//注意释放mSurface
            mCaptureRequest = null;
        }
        if (mSurface != null) {
            mSurface.release();//注意释放mSurface
            mSurface = null;
        }
        //也可以用onSurfaceTextureDestroyed这种方式释放SurfaceTexture 但是在上面的public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) 回调中你需要返回true或者自己执行 surface.release(); 这步资源释放很重要
        mTextureView.getSurfaceTextureListener().onSurfaceTextureDestroyed(mTextureView.getSurfaceTexture());
        mCameraDeviceStateCallback = null;
        mCameraCaptureSessionStateCallback = null;
        mCameraCaptureSessionCaptureCallback = null;
        mCameraManager = null;
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
        mCameraManager = null;
        if (mChildHandler != null) {
            mChildHandler.removeCallbacksAndMessages(null);
            mChildHandler = null;
        }
    }


    /**
     * @param paths      照片文件路径（本地路径）
     * @param delay      每张照片的持续时间（秒）
     * @param targetPath 视频文件路径
     * @param size       长度为2的数组，设置视频的分辨率: size[0]是宽，size[1]是高
     */
    public static boolean imageToVideo(List<String> paths, int delay, String targetPath, int[] size) {
        if (!paths.isEmpty()) {
            BitmapProvider bitmapProvider = new BitmapProvider(paths, size);
            bitmapProvider.init();
            if (!bitmapProvider.isAvailable()) {
                return false;
            }
            new AvcEncoder(bitmapProvider, 1f / delay, new File(targetPath), 0, null).start();
            return true;
        }
        return false;
    }

    /**
     * 启动拍照
     *
     * @param context  context
     * @param interval 自动拍照间隔
     */
    public static void start(Context context, int interval) {
        Intent starter = new Intent(context, RecordCameraActivity.class);
        starter.putExtra("interval", interval);
        context.startActivity(starter);
    }
}
